package com.csaba.swing.model;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Locale;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import com.csaba.swing.MainWindow;
import com.csaba.swing.gui.util.TableSizeContainer;
import com.csaba.swing.gui.util.WindowSizeContanier;
import com.csaba.util.LoggerHelper;
import com.csaba.util.encryption.EncryptedStore;

public final class Config
{
	private static Logger logger = LoggerHelper.getDefaultLogger();

	private static final String PARAM_LOG_LEVEL = MainWindow.getString("Config.0"); //$NON-NLS-1$
	private static final String PARAM_LOG_FILE_LOGGING = MainWindow.getString("Config.1"); //$NON-NLS-1$
	private static final String PARAM_HTTPS_PROXY_PORT = "https.proxyPort"; //$NON-NLS-1$
	private static final String PARAM_HTTPS_PROXY_HOST = "https.proxyHost"; //$NON-NLS-1$
	private static final String PARAM_LOCALE = "locale"; //$NON-NLS-1$
	private static final String PARAM_LOOKANDFEEL = "lookAndFeel"; //$NON-NLS-1$
	private static final String PARAM_WINDOWPOSITIONS = "window.positions"; //$NON-NLS-1$
	private static final String PARAM_COLUMNWIDTHS = "column.widths"; //$NON-NLS-1$
	private static final String PARAM_SECURE_REGISTRY = "secure.registry"; //$NON-NLS-1$
	private static final String PARAM_OPEN_ON_STARTUP = "open.on.startup"; //$NON-NLS-1$

	public final static String CONFIG_FILE = "csaba.conf"; //$NON-NLS-1$

	private String locale = "hu"; //$NON-NLS-1$
	private String httpsProxyHost = ""; //$NON-NLS-1$
	private String httpsProxyPort = ""; //$NON-NLS-1$
	private Level logLevel = Level.INFO;
	private boolean fileLogging = false;
	private String lookAndFeel = ""; //$NON-NLS-1$
	private String windowPositions = ""; //$NON-NLS-1$
	private String columnWidths = ""; //$NON-NLS-1$
	private String secureRegistry = ""; //$NON-NLS-1$
	private boolean openOnStartup = true;

	public static Config config = new Config();

	public static Config getInstance()
	{
		return config;
	}

	public static void loadConfig() throws IOException
	{
		final Properties properties = new Properties();
		final InputStream stream = new FileInputStream(CONFIG_FILE);
		properties.load(stream);
		stream.close();

		config.setLocale(properties.getProperty(PARAM_LOCALE, "hu")); //$NON-NLS-1$
		config.setHttpsProxyHost(properties.getProperty(PARAM_HTTPS_PROXY_HOST, "")); //$NON-NLS-1$
		config.setHttpsProxyPort(properties.getProperty(PARAM_HTTPS_PROXY_PORT, "")); //$NON-NLS-1$
		config.setFileLogging(Boolean.parseBoolean(properties.getProperty(PARAM_LOG_FILE_LOGGING, "false"))); //$NON-NLS-1$
		config.setLookAndFeel(properties.getProperty(PARAM_LOOKANDFEEL, UIManager.getSystemLookAndFeelClassName()));
		config.setWindowPositions(properties.getProperty(PARAM_WINDOWPOSITIONS, config.getWindowPositions()));
		config.setColumnWidths(properties.getProperty(PARAM_COLUMNWIDTHS, config.getColumnWidths()));
		config.setSecureRegistry(properties.getProperty(PARAM_SECURE_REGISTRY, config.getSecureRegistry()));
		config.setOpenOnStartup(Boolean.parseBoolean(properties.getProperty(PARAM_OPEN_ON_STARTUP, "true"))); //$NON-NLS-1$

		try
		{
			config.setLogLevel(Level.parse(properties.getProperty(PARAM_LOG_LEVEL, "INFO"))); //$NON-NLS-1$
		}
		catch ( final Exception e )
		{
			logger.log(Level.SEVERE, "Invalid log level in config.", e); //$NON-NLS-1$
		}
	}

	public static void saveConfig() throws IOException
	{
		final Properties properties = new Properties();
		properties.setProperty(PARAM_LOCALE, config.getLocale());
		properties.setProperty(PARAM_HTTPS_PROXY_HOST, config.getHttpsProxyHost());
		properties.setProperty(PARAM_HTTPS_PROXY_PORT, config.getHttpsProxyPort());
		properties.setProperty(PARAM_LOG_FILE_LOGGING, String.valueOf(config.isFileLogging()));
		properties.setProperty(PARAM_LOG_LEVEL, String.valueOf(config.getLogLevel()));
		properties.setProperty(PARAM_LOOKANDFEEL, config.getLookAndFeel());
		properties.setProperty(PARAM_WINDOWPOSITIONS, config.getWindowPositions());
		properties.setProperty(PARAM_COLUMNWIDTHS, config.getColumnWidths());
		properties.setProperty(PARAM_SECURE_REGISTRY, config.getSecureRegistry());
		properties.setProperty(PARAM_OPEN_ON_STARTUP, String.valueOf(config.isOpenOnStartup()));

		final OutputStream stream = new FileOutputStream(CONFIG_FILE);
		properties.store(stream, "Config of CSABA Swing"); //$NON-NLS-1$
		stream.close();
	}

	public Config()
	{
		// empty private constructor to avoid instantiation from elsewhere
	}

	public String getLocale()
	{
		return locale;
	}

	public void setLocale( final String locale )
	{
		if ( locale != null && locale.length() == 2 )
		{
			this.locale = locale;

			//set locale
			final Locale[] available = Locale.getAvailableLocales();
			boolean found = false;
			for ( int i = 0; i < available.length; i++ )
			{
				if ( available[i].getLanguage().equals(locale) )
				{
					Locale.setDefault(available[i]);
					found = true;
					break;
				}
			}
			if ( !found )
			{
				Locale.setDefault(new Locale(locale));
			}
		}
		else
		{
			throw new IllegalArgumentException(MainWindow.getString("Config.msg.invalidLanguage", locale)); //$NON-NLS-1$
		}
	}

	public String getHttpsProxyHost()
	{
		return httpsProxyHost;
	}

	public void setHttpsProxyHost( final String httpsProxyHost )
	{
		this.httpsProxyHost = httpsProxyHost;
		System.setProperty(PARAM_HTTPS_PROXY_HOST, httpsProxyHost);
	}

	public String getHttpsProxyPort()
	{
		return httpsProxyPort;
	}

	public void setHttpsProxyPort( final String httpsProxyPort )
	{
		this.httpsProxyPort = httpsProxyPort;
		System.setProperty(PARAM_HTTPS_PROXY_PORT, httpsProxyPort);
	}

	public Level getLogLevel()
	{
		return logLevel;
	}

	public boolean isFileLogging()
	{
		return fileLogging;
	}

	public void setLogLevel( final Level logLevel )
	{
		this.logLevel = logLevel;
		LoggerHelper.setLogLevel(logLevel);
	}

	public void setFileLogging( final boolean fileLogging )
	{
		this.fileLogging = fileLogging;
		//set file logging
		if ( fileLogging )
		{//file logging
			LoggerHelper.setFileLogging();
		}
		else
		{//consol logging
			LoggerHelper.setConsoleLogging();
		}

	}

	public String getLookAndFeel()
	{
		return lookAndFeel;
	}

	public void setLookAndFeel( final String lookAndFeel )
	{
		try
		{
			if ( !this.lookAndFeel.equals(lookAndFeel) )
			{
				final JFrame frame = MainWindow.getFrame();
				if ( frame != null && frame.isDisplayable() )
				{
					//do nothing
				}
				else
				{
					UIManager.setLookAndFeel(lookAndFeel);
					if ( frame != null )
						SwingUtilities.updateComponentTreeUI(frame);
				}
				this.lookAndFeel = lookAndFeel;
			}
		}
		catch ( final Exception ex )
		{
			logger.log(Level.SEVERE, "Unable to set look and feel based on the config file - " + lookAndFeel, ex); //$NON-NLS-1$
		}
	}

	public String getWindowPositions()
	{
		windowPositions = WindowSizeContanier.getInstance().toString();
		return windowPositions;
	}

	public void setWindowPositions( final String windowPositions )
	{
		this.windowPositions = windowPositions;
		WindowSizeContanier.getInstance().parseString(windowPositions);
	}

	public String getColumnWidths()
	{
		columnWidths = TableSizeContainer.getInstance().toString();
		return columnWidths;
	}

	public void setColumnWidths( final String columnWidths )
	{
		this.columnWidths = columnWidths;
		TableSizeContainer.getInstance().parseString(columnWidths);
	}

	public void setSecureRegistry( final String secureRegistry )
	{
		this.secureRegistry = secureRegistry;
		try
		{
			EncryptedStore.getInstance().setContent(secureRegistry);
		}
		catch ( final Exception ex )
		{
			logger.log(Level.SEVERE, "Unable to initialize EncryptedStore from Config: " + secureRegistry, ex); //$NON-NLS-1$
		}
	}

	public String getSecureRegistry()
	{
		try
		{
			this.secureRegistry = EncryptedStore.getInstance().toBASE64String();
		}
		catch ( final Exception ex )
		{
			logger.log(Level.SEVERE, "Unable to serialize EncryptedStore.", ex); //$NON-NLS-1$
			try
			{
				EncryptedStore.getInstance().debugKeys(Level.SEVERE);
			}
			catch ( final Exception ex2 )
			{
				logger.log(Level.FINE, "Unable to generate key list.", ex); //$NON-NLS-1$
			}
			secureRegistry = ""; //$NON-NLS-1$
		}
		return secureRegistry;
	}

	public void setOpenOnStartup( final boolean openOnStartup )
	{
		this.openOnStartup = openOnStartup;
	}

	public boolean isOpenOnStartup()
	{
		return openOnStartup;
	}

}
